package detect.parse.tree;

import java.util.*;

import detect.parse.pattern.MethodsPattern;
import detect.parse.tree.token.*;

public class FunctionDeclareExpression extends Expression{
	public TokenList funBody=null;
	public Token funName=null;
	public Token returnType=null;
	public TokenList args=null;
	
	@Override
	public String toString(){
		StringBuilder sb=new StringBuilder();
		
		if(returnType!=null){
			sb.append(returnType.toString());
			sb.append(" ");
		}
		sb.append(funName.toString());
		sb.append("(");
		sb.append(args.toString());
		sb.append("){...}");
		return sb.toString();
	}
	
	
	HashMap<MethodsPattern,MethodsPattern> patternMap=new HashMap<MethodsPattern,MethodsPattern>();
	
	public BlockExpression body=null;
	
	public TreeType getType(){
		return TreeType.FunctionDeclareType;
	}
	
	@Override
	public void findInnerPatterns(){
		body.findInnerPatterns();
		patterns=body.patterns;
		
		MethodsPattern temp=new MethodsPattern(null,null,MethodsPattern.SEQUENCE_CALL);
		
		for(MethodsPattern p: patterns){
			patternMap.put(p,p);
		}
		
		Set<Map.Entry<String, List<FunctionCallExpression>>> returnVarEntrySet=FunctionCallManager.returnVarEntrySet();
		for(Map.Entry<String, List<FunctionCallExpression>> returnVarEntry : returnVarEntrySet){
			String returnVar=returnVarEntry.getKey();
			List<FunctionCallExpression> returnFunList=returnVarEntry.getValue();
			HashMap<FunctionCallExpression,Integer> argFunMap=FunctionCallManager.getArgFunctionMap(returnVar);
			
			for(FunctionCallExpression returnFun: returnFunList){
				for(Map.Entry<FunctionCallExpression,Integer> argFunEntry: argFunMap.entrySet()){
					FunctionCallExpression argFun=argFunEntry.getKey();
					Integer argPos=argFunEntry.getValue();
					if(isFunctionCallSequence(returnFun,argFun)){
						temp.left_fun_exp=returnFun;
						temp.right_fun_exp=argFun;
						
						MethodsPattern p=patternMap.get(temp);
						if(p==null){
							p=new MethodsPattern(returnFun,argFun,MethodsPattern.RETURN_VAR);
							patternMap.put(p, p);
						}
						p.setReturnArgPos(argPos);		
					}
				}
			}
		}
		
		patterns.clear();
		patterns.addAll(patternMap.keySet());
	}
	
	public boolean isFunctionCallSequence(FunctionCallExpression left,FunctionCallExpression right){
		if(   	(left.begionPosition()<right.begionPosition() &&
				left.begionPosition()+left.length() < right.begionPosition())
			||
				(left.begionPosition()>right.begionPosition() &&
				left.begionPosition()+left.length() < right.begionPosition()+right.length())){
			return true;
		}
		return false;
	}

	public FunctionDeclareExpression(TokenList _tokenList,Token _funName,Token _returnType,TokenList _args,TokenList _funBody){
		tokenList=_tokenList;
		funName=_funName;
		returnType=_returnType;
		funBody=_funBody;
		args=_args;
	}
	
	public void parseDetail(){
		body=(BlockExpression)ExpressionFactory.blockExpInstance.getExpression(funBody);
	}
	
}
